package service

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"os"
	"path/filepath"
	"strings"
	"time"

	"markedit/internal/model"

	"github.com/google/uuid"
	"github.com/sirupsen/logrus"
)

type FileService struct {
	dataDir string
	logger  *logrus.Logger
}

func NewFileService(dataDir string, logger *logrus.Logger) *FileService {
	return &FileService{
		dataDir: dataDir,
		logger:  logger,
	}
}

// CreateDocument 创建新文档
func (fs *FileService) CreateDocument(title, content string, folderID string) (*model.Document, error) {
	doc := &model.Document{
		ID:        uuid.New().String(),
		Title:     title,
		Content:   content,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
		Tags:      []string{},
		FolderID:  folderID,
		Size:      int64(len(content)),
		Type:      "markdown",
	}

	err := fs.saveDocument(doc)
	if err != nil {
		fs.logger.Errorf("Failed to create document: %v", err)
		return nil, err
	}

	fs.logger.Infof("Document created: %s", doc.ID)
	return doc, nil
}

// GetDocument 获取文档
func (fs *FileService) GetDocument(id string) (*model.Document, error) {
	filePath := filepath.Join(fs.dataDir, "documents", id+".json")
	
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("document not found: %s", id)
		}
		return nil, err
	}

	var doc model.Document
	err = json.Unmarshal(data, &doc)
	if err != nil {
		return nil, err
	}

	return &doc, nil
}

// UpdateDocument 更新文档
func (fs *FileService) UpdateDocument(id string, title, content string) (*model.Document, error) {
	doc, err := fs.GetDocument(id)
	if err != nil {
		return nil, err
	}

	doc.Title = title
	doc.Content = content
	doc.UpdatedAt = time.Now()
	doc.Size = int64(len(content))

	err = fs.saveDocument(doc)
	if err != nil {
		fs.logger.Errorf("Failed to update document: %v", err)
		return nil, err
	}

	fs.logger.Infof("Document updated: %s", doc.ID)
	return doc, nil
}

// DeleteDocument 删除文档
func (fs *FileService) DeleteDocument(id string) error {
	filePath := filepath.Join(fs.dataDir, "documents", id+".json")
	
	err := os.Remove(filePath)
	if err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("document not found: %s", id)
		}
		return err
	}

	fs.logger.Infof("Document deleted: %s", id)
	return nil
}

// ListDocuments 列出文档
func (fs *FileService) ListDocuments(folderID string) ([]*model.Document, error) {
	documentsDir := filepath.Join(fs.dataDir, "documents")
	
	files, err := ioutil.ReadDir(documentsDir)
	if err != nil {
		if os.IsNotExist(err) {
			return []*model.Document{}, nil
		}
		return nil, err
	}

	var documents []*model.Document
	for _, file := range files {
		if !strings.HasSuffix(file.Name(), ".json") {
			continue
		}

		id := strings.TrimSuffix(file.Name(), ".json")
		doc, err := fs.GetDocument(id)
		if err != nil {
			fs.logger.Warnf("Failed to load document %s: %v", id, err)
			continue
		}

		// 过滤文件夹
		if folderID != "" && doc.FolderID != folderID {
			continue
		}

		documents = append(documents, doc)
	}

	return documents, nil
}

// CreateFolder 创建文件夹
func (fs *FileService) CreateFolder(name, parentID string) (*model.Folder, error) {
	folder := &model.Folder{
		ID:        uuid.New().String(),
		Name:      name,
		ParentID:  parentID,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
		Path:      fs.buildFolderPath(name, parentID),
	}

	err := fs.saveFolder(folder)
	if err != nil {
		fs.logger.Errorf("Failed to create folder: %v", err)
		return nil, err
	}

	fs.logger.Infof("Folder created: %s", folder.ID)
	return folder, nil
}

// GetFolder 获取文件夹
func (fs *FileService) GetFolder(id string) (*model.Folder, error) {
	filePath := filepath.Join(fs.dataDir, "folders", id+".json")
	
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("folder not found: %s", id)
		}
		return nil, err
	}

	var folder model.Folder
	err = json.Unmarshal(data, &folder)
	if err != nil {
		return nil, err
	}

	return &folder, nil
}

// ListFolders 列出文件夹
func (fs *FileService) ListFolders(parentID string) ([]*model.Folder, error) {
	foldersDir := filepath.Join(fs.dataDir, "folders")
	
	files, err := ioutil.ReadDir(foldersDir)
	if err != nil {
		if os.IsNotExist(err) {
			return []*model.Folder{}, nil
		}
		return nil, err
	}

	var folders []*model.Folder
	for _, file := range files {
		if !strings.HasSuffix(file.Name(), ".json") {
			continue
		}

		id := strings.TrimSuffix(file.Name(), ".json")
		folder, err := fs.GetFolder(id)
		if err != nil {
			fs.logger.Warnf("Failed to load folder %s: %v", id, err)
			continue
		}

		// 过滤父文件夹
		if folder.ParentID != parentID {
			continue
		}

		folders = append(folders, folder)
	}

	return folders, nil
}

// DeleteFolder 删除文件夹
func (fs *FileService) DeleteFolder(id string) error {
	// 检查文件夹是否存在
	_, err := fs.GetFolder(id)
	if err != nil {
		return err
	}

	// 检查是否有子文件夹
	subFolders, err := fs.ListFolders(id)
	if err != nil {
		return err
	}
	if len(subFolders) > 0 {
		return fmt.Errorf("folder contains subfolders, cannot delete")
	}

	// 检查是否有文档
	documents, err := fs.ListDocuments(id)
	if err != nil {
		return err
	}
	if len(documents) > 0 {
		return fmt.Errorf("folder contains documents, cannot delete")
	}

	// 删除文件夹
	filePath := filepath.Join(fs.dataDir, "folders", id+".json")
	err = os.Remove(filePath)
	if err != nil {
		return err
	}

	fs.logger.Infof("Folder deleted: %s", id)
	return nil
}

// saveDocument 保存文档到文件
func (fs *FileService) saveDocument(doc *model.Document) error {
	documentsDir := filepath.Join(fs.dataDir, "documents")
	err := os.MkdirAll(documentsDir, 0755)
	if err != nil {
		return err
	}

	data, err := json.MarshalIndent(doc, "", "  ")
	if err != nil {
		return err
	}

	filePath := filepath.Join(documentsDir, doc.ID+".json")
	return ioutil.WriteFile(filePath, data, 0644)
}

// saveFolder 保存文件夹到文件
func (fs *FileService) saveFolder(folder *model.Folder) error {
	foldersDir := filepath.Join(fs.dataDir, "folders")
	err := os.MkdirAll(foldersDir, 0755)
	if err != nil {
		return err
	}

	data, err := json.MarshalIndent(folder, "", "  ")
	if err != nil {
		return err
	}

	filePath := filepath.Join(foldersDir, folder.ID+".json")
	return ioutil.WriteFile(filePath, data, 0644)
}

// buildFolderPath 构建文件夹路径
func (fs *FileService) buildFolderPath(name, parentID string) string {
	if parentID == "" {
		return name
	}

	parent, err := fs.GetFolder(parentID)
	if err != nil {
		return name
	}

	return filepath.Join(parent.Path, name)
}

// SearchDocuments 搜索文档
func (fs *FileService) SearchDocuments(keyword string) ([]*model.Document, error) {
	documents, err := fs.ListDocuments("")
	if err != nil {
		return nil, err
	}

	var results []*model.Document
	keyword = strings.ToLower(keyword)

	for _, doc := range documents {
		if strings.Contains(strings.ToLower(doc.Title), keyword) ||
			strings.Contains(strings.ToLower(doc.Content), keyword) {
			results = append(results, doc)
		}
	}

	return results, nil
}

// UploadFile 上传文件
func (fs *FileService) UploadFile(file multipart.File, header *multipart.FileHeader, folderID string) (*model.Document, error) {
	// 创建上传目录
	uploadDir := filepath.Join(fs.dataDir, "uploads")
	err := os.MkdirAll(uploadDir, 0755)
	if err != nil {
		return nil, fmt.Errorf("failed to create upload directory: %v", err)
	}

	// 生成唯一文件名
	fileID := uuid.New().String()
	ext := filepath.Ext(header.Filename)
	fileName := fileID + ext
	filePath := filepath.Join(uploadDir, fileName)

	// 创建目标文件
	dst, err := os.Create(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to create file: %v", err)
	}
	defer dst.Close()

	// 复制文件内容
	_, err = io.Copy(dst, file)
	if err != nil {
		return nil, fmt.Errorf("failed to save file: %v", err)
	}

	// 获取文件信息
	fileInfo, err := dst.Stat()
	if err != nil {
		return nil, fmt.Errorf("failed to get file info: %v", err)
	}

	// 创建文档记录
	doc := &model.Document{
		ID:        fileID,
		Title:     header.Filename,
		Content:   "", // 对于非文本文件，内容为空
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
		Tags:      []string{},
		FolderID:  folderID,
		Size:      fileInfo.Size(),
		Type:      "file",
		Name:      header.Filename,
	}

	// 如果是文本文件，读取内容
	if ext == ".md" || ext == ".txt" {
		content, err := ioutil.ReadFile(filePath)
		if err == nil {
			doc.Content = string(content)
			doc.Type = "markdown"
		}
	}

	// 保存文档记录
	err = fs.saveDocument(doc)
	if err != nil {
		// 如果保存失败，删除已上传的文件
		os.Remove(filePath)
		return nil, fmt.Errorf("failed to save document record: %v", err)
	}

	fs.logger.Infof("File uploaded: %s", header.Filename)
	return doc, nil
}